#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "l4rb.h"
#include "websocket.h"
#include "/root/ling/util/pq.h"

uint32_t ring_size = 1024;
uint32_t max_client = 3;
void conn_dump(struct L4rb *l4rb){
    /*
    P_(" Inten: [%d]\n", l4rb->inten_conn);
    for(int n=l4rb->max_conn; n--;){
    */
    int n = l4rb->inten_conn;
        printf("<> Client[%d] -- %ud -- %ud -- \"%d\"\n", n, l4rb->conn[n].rb_head, l4rb->conn[n].rb_tail, l4rb->conn[n].fd);
        /*
    }*/
}
int main(int argc, char *argv[]){
    if(argc >2){
        max_client = atoi(argv[1]);
        ring_size = atoi(argv[2]);
    }
    FILE *doc = fopen("./root.cap", "rb");
    char *doc_buff = malloc(500);
    int doc_size = fread(doc_buff, 1, 500, doc);
    fclose(doc);

    struct Ring *rb = malloc(sizeof(struct Ring) + ring_size);
    ring_init(rb, ring_size);
    struct L4rb *server= malloc(sizeof(struct L4rb)+sizeof(struct L4conn[max_client]));
    if(server == NULL)return -1;
    server->rb = rb;
    char addr[] = "0.0.0.0:80";
    if(l4rb_queue_init(server, max_client) == -1)
        goto fallback;
    if(l4rb_listen(server, addr) == -1)
        goto fallback;
    printf(" Up to %d clients, Ring free: %d\n", server->max_conn, RING_TAIL_SIZE(rb));
    /*  TODO:
     *  Implement WebSocket
     */
    uint32_t curr_client;
    char sec_key[50];
    char ws_response[1024];
    size_t ws_req_len = 0;
    size_t ws_res_len = 0;
    int handshake = 0;
    int opcodes = 0;
    for(;;){
        if((curr_client = l4rb_poll(server, -1))
                == INACTIVE_CONN) continue;
        char *data = l4rb_rx(server, 6);
        if(!data){
            l4rb_yield(server);
            continue;
        }
        if(handshake == 0){
            ws_req_len = l4rb_length(server);
            if(ws_header_get(data, ws_req_len, "Sec-WebSocket-Key", sec_key) <= 0) continue;
            printf("Client: %s\n", sec_key);
            ws_res_len = ws_handshake_response(ws_response, sec_key, 1024);
            if(ws_res_len <= 0) continue;
            l4rb_tx(server, ws_response, ws_res_len);
            handshake = 1;
            l4rb_drop(server, ws_req_len);
            l4rb_yield(server);
            continue;
        }
        ws_req_len = ws_read(data, 6, &opcodes);
        P_(" One frame of %li bytes, @%i ..", ws_req_len,
                server->conn[server->inten_conn].rb_head);
        if((data = l4rb_rx(server, ws_req_len))){
            ws_read(data, ws_req_len, &opcodes);
            printf(" received.\n");
        }else{
            l4rb_yield(server);
            printf(" incomplete.\n");
            continue;
        }
        conn_dump(server);
        size_t data_len = ws_frame_len(data);
        size_t offset = ws_framing(ws_response, data_len, 0, WS_FIN | WS_TEXT);
        ws_res_len = ws_write(ws_response, offset, ws_frame_data(data), data_len);
        l4rb_tx(server, ws_response, ws_res_len);
        P_(" <> %d Bytes sent.\n", ws_res_len);
        l4rb_drop(server, ws_req_len);
        P_(" Droped %li bytes.\n", ws_req_len);
        P_(" %li bytes free in Ring.\n", RING_TAIL_SIZE(server->rb));
        l4rb_yield(server);
    }
fallback:
    l4rb_queue_close(server);
    l4rb_close(server);
    free(rb);
    free(server);
    return 0;
}
